package com.gandong8.es.tool.core;

import com.gandong8.es.tool.util.EsUtil;
import lombok.Data;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Data
public class EsQuery<T extends EsDoc> {
    private T obj;
    private int from = 0;
    private int size = 50;
    private int timeout = 60;
    private String searchTxt ;
    private SortOrder sortOrder = SortOrder.DESC;
    private String sortField ;
    private Date beginTime;
    private Date endTime;
    private long totalHits;

    public EsQuery(T obj) {
        this.obj = obj;
    }
    public SearchRequest search() {
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(EsUtil.parseIndexName(this.obj.getClass()));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //Es通过index.max_result_window参数控制了能够获取的数据总数from+size的最大值，默认是10000条
        //由于数据需要从其它节点分别上报到协调节点,若请求的数据越多,会导致在协调节点占用分配给Es的堆内存和搜索排序时间越大。针对这种深度搜索，官方建议用Scroll or search_after
        builder.from(from);
        builder.size(size);
        builder.timeout(new TimeValue(timeout, TimeUnit.SECONDS));
        if(this.obj.esDocumentId() != null) {
            QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds(this.obj.esDocumentId());
            return searchRequest.source(builder.query(queryBuilder));
        }
        Map<String, Object> map = EsUtil.parseObjValue(this.obj);
        String sortTime = EsUtil.getSortTime(this.obj.getClass());
        //使用QueryBuilders进行查询
        BoolQueryBuilder queryBuilder =  QueryBuilders.boolQuery();
        if(sortTime != null) {
            if(beginTime!=null && endTime!=null ) {
                queryBuilder.must(QueryBuilders.rangeQuery(sortTime).from(beginTime).to(endTime).includeLower(true).includeUpper(true));
            } else if(beginTime == null) {
                queryBuilder.must(QueryBuilders.rangeQuery(sortTime).lte(endTime));
            } else {
                queryBuilder.must(QueryBuilders.rangeQuery(sortTime).gte(beginTime));
            }
        }
        builder.query(queryBuilder);
        //Term-level queries
        map.forEach((k,v)-> queryBuilder.must(QueryBuilders.termQuery(k, v)));
        builder.query(queryBuilder);
        if(sortField != null) {
            builder.sort(new FieldSortBuilder(sortField).order(sortOrder));
        }
        searchRequest.source(builder);
        return searchRequest;
    }




}
